/*
Copyright (c) 2010 Bill Davidsen (wdavidsen@yahoo.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing.Design;
using System.Web.UI;

namespace SCS.Web.UI.WebControls
{
	public sealed class ContextHotSpotCollection : IList, IStateManager 
	{
		private ArrayList hotSpots;
		private bool isTrackingViewState;
		private bool saveAll;
    
		internal ContextHotSpotCollection() 
		{
			hotSpots = new ArrayList();
		}
        
		public ContextHotSpot this[int index] 
		{
			get 
			{
				return (ContextHotSpot)hotSpots[index];
			}
		}

		object IList.this[int index] 
		{
			get 
			{
				return hotSpots[index];
			}
			set 
			{
				hotSpots[index] = (ContextHotSpot)value;
			}
		}
    
		public int Add(ContextHotSpot item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}
			
			hotSpots.Add(item);

			if (isTrackingViewState) 
			{
				((IStateManager)item).TrackViewState();
				item.SetDirty();
			}

			return hotSpots.Count - 1;
		}
        
		public void Clear() 
		{
			hotSpots.Clear();
			if (isTrackingViewState) 
			{
				saveAll = true;
			}
		}
            
		public bool Contains(ContextHotSpot item) 
		{
			if (item == null) 
			{
				return false;
			}
			return hotSpots.Contains(item);
		}

		public int IndexOf(ContextHotSpot item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}
			return hotSpots.IndexOf(item);
		}

		public void Insert(int index, ContextHotSpot item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}
			
			hotSpots.Insert(index,item);

			if (isTrackingViewState) 
			{
				((IStateManager)item).TrackViewState();
				saveAll = true;
			}
		}

		public void RemoveAt(int index) 
		{
			hotSpots.RemoveAt(index);
			if (isTrackingViewState) 
			{
				saveAll = true;
			}
		}
    
		public void Remove(ContextHotSpot item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}

			int index = IndexOf(item);
			if (index >= 0) 
			{
				RemoveAt(index);
			}
		}

		
		#region IEnumerable Implementation
		public IEnumerator GetEnumerator() 
		{
			return hotSpots.GetEnumerator();
		}
		#endregion IEnumerable Implementation

		#region ICollection Implementation
		[
		Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
		]
		public int Count 
		{
			get 
			{
				return hotSpots.Count;
			}
		}

		public void CopyTo(Array array, int index) 
		{
			hotSpots.CopyTo(array,index);
		}

		[
		Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
		]
		public bool IsSynchronized 
		{
			get 
			{
				return false;
			}
		}

		[
		Browsable(false),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
		]
		public object SyncRoot 
		{
			get 
			{
				return this;
			}
		}
		#endregion ICollection Implementation

		#region IList Implementation
		bool IList.IsFixedSize 
		{
			get 
			{
				return false;
			}
		}

		bool IList.IsReadOnly 
		{
			get 
			{
				return false;
			}
		}

		int IList.Add(object item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}
			if (!(item is ContextHotSpot)) 
			{
				throw new ArgumentException("item must be a ContextHotSpot");
			}

			return Add((ContextHotSpot)item);
		}

		void IList.Clear() 
		{
			Clear();
		}

		bool IList.Contains(object item) 
		{
			return Contains(item as ContextHotSpot);
		}

		int IList.IndexOf(object item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}
			if (!(item is ContextHotSpot)) 
			{
				throw new ArgumentException("item must be a ContextHotSpot");
			}

			return IndexOf((ContextHotSpot)item);
		}

		void IList.Insert(int index, object item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}
			if (!(item is ContextHotSpot)) 
			{
				throw new ArgumentException("item must be a ContextHotSpot");
			}

			Insert(index, (ContextHotSpot)item);
		}

		void IList.Remove(object item) 
		{
			if (item == null) 
			{
				throw new ArgumentNullException("item");
			}
			if (!(item is ContextHotSpot)) 
			{
				throw new ArgumentException("item must be a ContextHotSpot");
			}

			Remove((ContextHotSpot)item);
		}

		void IList.RemoveAt(int index) 
		{
			RemoveAt(index);
		}
		#endregion IList Implementation
       
		#region IStateManager Implementation
		bool IStateManager.IsTrackingViewState 
		{
			get 
			{
				return isTrackingViewState;
			}
		}

		void IStateManager.LoadViewState(object savedState) 
		{
			if (savedState == null) 
			{
				return;
			}

			if (savedState is Pair) 
			{
				// All items were saved.
				// Create new HotSpots collection using view state.
				saveAll = true;
				Pair p = (Pair)savedState;
				ArrayList types = (ArrayList) p.First;
				ArrayList states = (ArrayList) p.Second;
				int count = types.Count;

				hotSpots = new ArrayList(count);
				for (int i = 0; i < count; i++) 
				{
					ContextHotSpot hotSpot = null;
					if (((char)types[i]).Equals('c')) 
					//{
						hotSpot = new ContextHotSpot();
					//}
					//else 
					//{
						
					//}
					Add(hotSpot);
					((IStateManager)hotSpot).LoadViewState(states[i]);
				}
			}
			else 
			{
				// Load modified items.
				Triplet t = (Triplet) savedState;
				ArrayList indices = (ArrayList)t.First;
				ArrayList types = (ArrayList)t.Second;
				ArrayList states = (ArrayList)t.Third; 

				for (int i = 0 ;  i < indices.Count; i++) 
				{
					int index = (int)indices[i];
					if (index < this.Count) 
					{
						((IStateManager)hotSpots[index]).LoadViewState(states[i]);
					}
					else 
					{
						ContextHotSpot hotSpot = null;
						//if (((char)types[i]).Equals('c')) 
						//{
							hotSpot = new ContextHotSpot();
						//}
						//else 
						//{
							
						//}
						Add(hotSpot);
						((IStateManager)hotSpot).LoadViewState(states[i]);
					}
				}
			}
		}

		void IStateManager.TrackViewState() 
		{
			isTrackingViewState = true;

			foreach (ContextHotSpot hotSpot in hotSpots) 
			{
				((IStateManager)hotSpot).TrackViewState();
			}
		}

		object IStateManager.SaveViewState() 
		{
			if (saveAll == true) 
			{ 
				// Save all items.
				ArrayList types = new ArrayList(Count);
				ArrayList states = new ArrayList(Count);
				for (int i = 0; i < Count; i++) 
				{
					ContextHotSpot hotSpot = (ContextHotSpot)hotSpots[i];
					hotSpot.SetDirty();

					//if (hotSpot is ContextHotSpot) 
					//{
						types.Add('c');
					//}
					//else 
					//{
					//	types.Add('r');
					//}
					states.Add(((IStateManager)hotSpot).SaveViewState());
				}
				if (types.Count > 0) 
				{
					return new Pair(types, states);
				}
				else 
				{
					return null;
				}
			}
			else 
			{ 
				// Save only the dirty items.
				ArrayList indices = new ArrayList();
				ArrayList types = new ArrayList();
				ArrayList states = new ArrayList();
             
				for (int i = 0; i < Count; i++) 
				{
					ContextHotSpot hotSpot = (ContextHotSpot)hotSpots[i];
					object state = ((IStateManager)hotSpot).SaveViewState();
					if (state != null) 
					{
						states.Add(state);
						indices.Add(i);
						
						//if (hotSpot is ContextHotSpot) 
						//{
							types.Add('c');
						//}
						//else 
						//{
						//	types.Add('r');
						//}
					}
				}

				if (indices.Count > 0) 
				{
					return new Triplet(indices, types, states);
				}

				return null;
			}
		}                   
		#endregion IStateManager Implementation
	}
}
